package com.cupdata.zicon.jdk7concurrent.chapter2;



import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;



/**
 * using the lock() method. When a
thread (A) calls this method, if no other thread has the control of the lock, the method gives
the thread (A) the control of the lock and returns immediately to permit the execution of the
critical section to this thread. Otherwise, if there is another thread (B) executing the critical
section controlled by this lock, the lock() method puts the thread (A) to sleep until the
thread (B) finishes the execution of the critical section.

The Lock interface (and the ReentrantLock class) includes another method to get the
control of the lock. It's the tryLock() method. The biggest difference with the lock()
method is that this method, if the thread that uses it can't get the control of the Lock
interface, returns immediately and doesn't put the thread to sleep. This method returns a
boolean value, true if the thread gets the control of the lock, and false if not.

You have to be very careful with the use of Locks to avoid deadlocks.

 * @author SunYabing
 *
 */
public class LockTest {

	//@Test
	public static void main(String[] args) {
		PrintQueue printQueue = new PrintQueue();

		Thread thread[] = new Thread[10];
		for (int i = 0; i < 10; i++) {
			thread[i] = new Thread(new Job(printQueue), "Thread " + i);
		}

		for (int i = 0; i < 10; i++) {
			thread[i].start();
		}
	}

}

class PrintQueue {
	private final Lock queueLock = new ReentrantLock();

	public void printJob(Object document) {
		//queueLock.lock();
		if(!queueLock.tryLock()){
			return;
		} else {			
		try {
			Long duration = (long) (Math.random() * 10000);
			System.out.println(Thread.currentThread().getName() + ":"
					+ "PrintQueue: Printing a Job during " + (duration / 1000)
					+ " seconds");
			Thread.sleep(duration);
		} catch (InterruptedException e) {
			e.printStackTrace();
		} finally {
			queueLock.unlock();
		}
		}
	}
}

class Job implements Runnable {
	private PrintQueue printQueue;

	public Job(PrintQueue printQueue) {
		this.printQueue = printQueue;
	}

	@Override
	public void run() {
		System.out.printf("%s: Going to print a document\n", Thread
				.currentThread().getName());
		printQueue.printJob(new Object());
		System.out.printf("%s: The document has been printed\n", Thread
				.currentThread().getName());
	}
}
